#include "icsearch.hpp"
#include "user.hxx"     // search返回的vector<User>使用到
#include "message.hxx"

namespace im {
// 构建esclient对象
class ESClientFactory {
    public:
        static std::shared_ptr<elasticlient::Client> create(const std::vector<std::string>& host_list) 
        {
            return std::make_shared<elasticlient::Client>(host_list);
        }
};
class ESUser 
{
    private:
        std::shared_ptr<elasticlient::Client> _es_client;
    public:
        using ptr = std::shared_ptr<ESUser>;
        
        ESUser(const std::shared_ptr<elasticlient::Client> &client)
            : _es_client(client)
        {}

        // 添加索引：不再让用户指明，我们写死，因为es存在的意义就是用来快速检索这几个信息的
        bool createIndex() 
        {
            bool ret = ESIndex(_es_client, "user")
                .append("user_id", "keyword", "standard", true) // user_id需要建立索引，整体不分词
                .append("nickname")                             // 采用append的缺省参数，不建立索引，中文分词
                .append("phone", "keyword", "standard", true)   // phone需要建立索引，整体不分词
                .append("description", "text", "standard", false)   // 采用append的缺省参数，不建立索引，中文分词
                .append("avatar_id", "keyword", "standard", false)  // 采用append的缺省参数，不建立索引，不分词
                .create();
            if (ret == false) {
                LOG_INFO("用户信息索引创建失败!");
                return false;
            }
            LOG_INFO("用户信息索引创建成功!");
            return true;
        }
        // 添加数据
        bool appendData(const std::string &uid, const std::string &phone, const std::string &nickname,
                        const std::string &description, const std::string &avatar_id) 
        {
            bool ret = ESInsert(_es_client, "user")
                .append("user_id", uid)
                .append("nickname", nickname)
                .append("phone", phone)
                .append("description", description)
                .append("avatar_id", avatar_id)
                .insert(uid);
            if (ret == false) {
                LOG_ERROR("用户数据插入/更新失败!");
                return false;
            }
            LOG_INFO("用户数据新增/更新成功!");
            return true;
        }
        // 检索
        std::vector<User> search(const std::string &key, const std::vector<std::string> &uid_list) 
        {
            std::vector<User> res;
            Json::Value json_user = ESSearch(_es_client, "user")
                .append_should("phone.keyword", key)   // 手机号全字匹配
                .append_should("user_id.keyword", key) // user_id全字匹配
                .append_should("nickname", key)        // 个性标签分词匹配
                .append_must_not("user_id.keyword", uid_list) // 不检索uid_list包含的uid用户相关信息
                .search();
            if (json_user.isArray() == false) {
                LOG_ERROR("用户搜索结果为空，或者结果不是数组类型");
                return res;
            }
            int sz = json_user.size();
            LOG_DEBUG("检索结果条目数量：{}", sz);
            for (int i = 0; i < sz; i++) 
            {
                // 填充查询结果
                User user; // user.hxx封装的odb类对象
                user.user_id(json_user[i]["_source"]["user_id"].asString());
                user.nickname(json_user[i]["_source"]["nickname"].asString());
                user.description(json_user[i]["_source"]["description"].asString());
                user.phone(json_user[i]["_source"]["phone"].asString());
                user.avatar_id(json_user[i]["_source"]["avatar_id"].asString());
                // 尾插至vector中，最后返回
                res.push_back(user);
            }
            return res;
        }
};
class ESMessage
{
public:
    using ptr = std::shared_ptr<ESMessage>;
    ESMessage(const std::shared_ptr<elasticlient::Client> &es_client)
        : _es_client(es_client)
    {}
    bool createIndex() {
        bool ret = ESIndex(_es_client, "message")
            .append("user_id", "keyword", "standard", false)
            .append("chat_session_id", "keyword", "standard", true) // 会话ID搜索时建立索引，其他的不建立索引
            .append("message_id", "keyword", "standard", false)
            .append("create_time", "long", "standard", false)
            .append("content") // 采用缺省参数，text、ik_max_word、true
            .create();
        if (ret == false) {
            LOG_ERROR("消息信息索引创建失败!");
            return false;
        }
        LOG_INFO("消息信息索引创建成功!");
        return true;
    }
    bool appendData(const std::string &user_id, const std::string &message_id,
            const long create_time, const std::string &chat_session_id, const std::string &content) 
    {
        bool ret = ESInsert(_es_client, "message")
            .append("message_id", message_id)
            .append("create_time", create_time)
            .append("user_id", user_id)
            .append("chat_session_id", chat_session_id)
            .append("content", content)
            .insert(message_id);
        if (ret == false) {
            LOG_ERROR("消息数据插入/更新失败!");
            return false;
        }
        LOG_INFO("消息数据新增/更新成功!");
        return true;
    }
    bool remove(const std::string &mid) 
    {
        bool ret = ESRemove(_es_client, "message").remove(mid);
        if (ret == false) {
            LOG_ERROR("消息数据删除失败!");
            return false;
        }
        LOG_INFO("消息数据删除成功!");
        return true;
    }
    std::vector<im::Message> search(const std::string &key, const std::string &ssid) 
    {
        std::vector<im::Message> res;
        Json::Value json_user = ESSearch(_es_client, "message")
            .append_must_term("chat_session_id.keyword", ssid) // 必须匹配的key，会话ID一定是我指定的会话ID
            .append_must_match("content", key)  // 必须要匹配的
            .search();
        if (json_user.isArray() == false) {
            LOG_ERROR("用户搜索结果为空，或者结果不是数组类型");
            return res;
        }
        int sz = json_user.size();
        LOG_DEBUG("检索结果条目数量：{}", sz);
        for (int i = 0; i < sz; i++) {
            im::Message message;
            message.user_id(json_user[i]["_source"]["user_id"].asString());
            message.message_id(json_user[i]["_source"]["message_id"].asString());
            boost::posix_time::ptime ctime(boost::posix_time::from_time_t(
                json_user[i]["_source"]["create_time"].asInt64()));
            message.create_time(ctime);
            message.session_id(json_user[i]["_source"]["chat_session_id"].asString());
            message.content(json_user[i]["_source"]["content"].asString());
            res.push_back(message);
        }
        return res;
    }
private:
    std::shared_ptr<elasticlient::Client> _es_client;
};
}